﻿using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.CodeStash_Addin;
using Rhino.Mocks;
using CodeStash.Addin.Core.Interfaces;
using Microsoft.CodeStash_Addin.Core;
using CodeStash.Common.DTOS;

namespace CodeStash.Addin.Test
{
    /// <summary>
    /// Summary description for SnippetViewModelTests
    /// </summary>
    [TestClass]
    public class SnippetViewModelTests
    {
        private SnippetViewModel vm;

        public SnippetViewModelTests()
        {
            //
            // TODO: Add constructor logic here
            //
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        #region Additional test attributes
        //
        // You can use the following additional attributes as you write your tests:
        //
        // Use ClassInitialize to run code before running the first test in the class
        // [ClassInitialize()]
        // public static void MyClassInitialize(TestContext testContext) { }
        //
        // Use ClassCleanup to run code after all tests in a class have run
        // [ClassCleanup()]
        // public static void MyClassCleanup() { }
        //
        private IRestService service;
        // Use TestInitialize to run code before running each test 
        [TestInitialize()]
        public void MyTestInitialize()
        {
            service = MockRepository.GenerateStub<IRestService>();
            ServiceContainer.Instance.Add<IRestService>(service);
        }
        #endregion

        [TestMethod]
        public void Ensure_VM_Can_be_created()
        {
            vm = new SnippetViewModel();
            Assert.IsNotNull(vm);
        }

        private void AddLanguages()
        {
            List<JSONLanguage> languages = new List<JSONLanguage>();
            languages.Add(new JSONLanguage(1, "C#"));
            languages.Add(new JSONLanguage(2, "C++"));
            JSONLanguagesResult result = new JSONLanguagesResult(languages, "No error");
            service.Stub(s => s.RetrieveLanguages()).Return(result);
        }

        private void AddGroups()
        {
            List<JSONGrouping> groups = new List<JSONGrouping>();
            groups.Add(new JSONGrouping(1, "My group"));
            groups.Add(new JSONGrouping(2, "Another group"));
            JSONGroupingResult result = new JSONGroupingResult(groups, "No error");
            service.Stub(s => s.RetrieveGroups()).Return(result);
        }

        [TestMethod]
        public void Ensure_Languages_can_be_retrieved()
        {
            AddLanguages();
            // First of all, we need to set some things up with the mocker.
            vm = new SnippetViewModel();
            // There should be 2 languages in the list.
            Assert.AreEqual(vm.Languages.Count, 2);

            service.VerifyAllExpectations();
        }

        [TestMethod]
        public void Ensure_groups_can_be_retrieved()
        {
            AddGroups();
            // First of all, we need to set some things up with the mocker.
            vm = new SnippetViewModel();
            vm.Groups.MoveCurrentToNext();
            Assert.AreEqual(vm.Groups.CurrentPosition, 1);

            service.VerifyAllExpectations();
        }

        #region selected language notification tests
        [TestMethod]
        public void Ensure_notification_raised_on_selected_language()
        {
            AddLanguages();
            vm = new SnippetViewModel();
            bool languageChosen = false;
            vm.PropertyChanged += (s, e) =>
                {
                    if (e.PropertyName == "SelectedLanguage")
                    {
                        languageChosen = true;
                    }
                };
            var language = vm.Languages[1];
            vm.SelectedLanguage = language;

            Assert.IsTrue(languageChosen);
        }

        [TestMethod]
        public void Ensure_notification_not_raised_on_selected_language_when_selection_does_not_change()
        {
            AddLanguages();
            vm = new SnippetViewModel();
            bool languageChosen = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "SelectedLanguage")
                {
                    languageChosen = true;
                }
            };
            var language = vm.Languages[1];
            vm.SelectedLanguage = language;

            // Reset the language chosen flag which will have previously been triggered.
            languageChosen = false;
            // At this stage, we should already have a selected language. By using the same
            // selection, we should not get a notification.
            vm.SelectedLanguage = language;

            Assert.IsFalse(languageChosen);
        }

        [TestMethod]
        public void Selected_language_change_should_set_property()
        {
            AddLanguages();
            vm = new SnippetViewModel();
            var language = vm.Languages[1];
            vm.SelectedLanguage = language;

            Assert.AreEqual(vm.SelectedLanguage, language);
        }
        #endregion

        #region selected group notification tests
        [TestMethod]
        public void Ensure_notification_raised_on_selected_group()
        {
            AddGroups();
            vm = new SnippetViewModel();
            bool groupChosen = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "SelectedGroup")
                {
                    groupChosen = true;
                }
            };
            vm.Groups.MoveCurrentToFirst();
            var group = vm.Groups.CurrentItem as JSONGrouping;
            vm.SelectedGroup = group;

            Assert.IsTrue(groupChosen);
        }

        [TestMethod]
        public void Ensure_notification_not_raised_on_selected_group_when_selection_does_not_change()
        {
            AddGroups();
            vm = new SnippetViewModel();
            bool groupChosen = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "SelectedGroup")
                {
                    groupChosen = true;
                }
            };
            vm.Groups.MoveCurrentToFirst();
            var group = vm.Groups.CurrentItem as JSONGrouping;
            vm.SelectedGroup = group;

            // Reset the language chosen flag which will have previously been triggered.
            groupChosen = false;
            // At this stage, we should already have a selected language. By using the same
            // selection, we should not get a notification.
            vm.SelectedGroup = group;

            Assert.IsFalse(groupChosen);
        }

        [TestMethod]
        public void Selected_group_change_should_set_property()
        {
            AddGroups();
            vm = new SnippetViewModel();
            vm.Groups.MoveCurrentToFirst();
            var group = vm.Groups.CurrentItem as JSONGrouping;
            vm.SelectedGroup = group;

            Assert.AreEqual(vm.SelectedGroup, group);
        }
        #endregion

        #region title notification tests
        [TestMethod]
        public void Changing_title_raises_notification()
        {
            vm = new SnippetViewModel();
            bool titleChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Title")
                {
                    titleChanged = true;
                }
            };
            vm.Title = "My test";
            Assert.IsTrue(titleChanged);
        }

        [TestMethod]
        public void Changing_title_to_the_same_value_does_not_raise_notification()
        {
            vm = new SnippetViewModel();
            bool titleChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Title")
                {
                    titleChanged = true;
                }
            };
            vm.Title = "My test";
            titleChanged = false;
            vm.Title = "My test";

            Assert.IsFalse(titleChanged);
        }

        [TestMethod]
        public void Changing_title_sets_value()
        {
            vm = new SnippetViewModel();
            vm.Title = "My test";
            Assert.AreEqual(vm.Title, "My test");
        }
        #endregion

        #region tag notification tests
        [TestMethod]
        public void Changing_tag_raises_notification()
        {
            vm = new SnippetViewModel();
            bool TagChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Tag")
                {
                    TagChanged = true;
                }
            };
            vm.Tag = "My test";
            Assert.IsTrue(TagChanged);
        }

        [TestMethod]
        public void Changing_tag_to_the_same_value_does_not_raise_notification()
        {
            vm = new SnippetViewModel();
            bool TagChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Tag")
                {
                    TagChanged = true;
                }
            };
            vm.Tag = "My test";
            TagChanged = false;
            vm.Tag = "My test";

            Assert.IsFalse(TagChanged);
        }

        [TestMethod]
        public void Changing_tag_sets_value()
        {
            vm = new SnippetViewModel();
            vm.Tag = "My test";
            Assert.AreEqual(vm.Tag, "My test");
        }
        #endregion

        #region category notification tests
        [TestMethod]
        public void Changing_Category_raises_notification()
        {
            vm = new SnippetViewModel();
            bool CategoryChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Category")
                {
                    CategoryChanged = true;
                }
            };
            vm.Category = "My test";
            Assert.IsTrue(CategoryChanged);
        }

        [TestMethod]
        public void Changing_Category_to_the_same_value_does_not_raise_notification()
        {
            vm = new SnippetViewModel();
            bool CategoryChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Category")
                {
                    CategoryChanged = true;
                }
            };
            vm.Category = "My test";
            CategoryChanged = false;
            vm.Category = "My test";

            Assert.IsFalse(CategoryChanged);
        }

        [TestMethod]
        public void Changing_Category_sets_value()
        {
            vm = new SnippetViewModel();
            vm.Category = "My test";
            Assert.AreEqual(vm.Category, "My test");
        }
        #endregion

        #region NewGroup notification tests
        [TestMethod]
        public void Changing_NewGroup_raises_notification()
        {
            vm = new SnippetViewModel();
            bool NewGroupChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "NewGroup")
                {
                    NewGroupChanged = true;
                }
            };
            vm.NewGroup = "My test";
            Assert.IsTrue(NewGroupChanged);
        }

        [TestMethod]
        public void Changing_NewGroup_to_the_same_value_does_not_raise_notification()
        {
            vm = new SnippetViewModel();
            bool NewGroupChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "NewGroup")
                {
                    NewGroupChanged = true;
                }
            };
            vm.NewGroup = "My test";
            NewGroupChanged = false;
            vm.NewGroup = "My test";

            Assert.IsFalse(NewGroupChanged);
        }

        [TestMethod]
        public void Changing_NewGroup_sets_value()
        {
            vm = new SnippetViewModel();
            vm.NewGroup = "My test";
            Assert.AreEqual(vm.NewGroup, "My test");
        }
        #endregion

        #region Description notification tests
        [TestMethod]
        public void Changing_Description_raises_notification()
        {
            vm = new SnippetViewModel();
            bool DescriptionChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Description")
                {
                    DescriptionChanged = true;
                }
            };
            vm.Description = "My test";
            Assert.IsTrue(DescriptionChanged);
        }

        [TestMethod]
        public void Changing_Description_to_the_same_value_does_not_raise_notification()
        {
            vm = new SnippetViewModel();
            bool DescriptionChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "Description")
                {
                    DescriptionChanged = true;
                }
            };
            vm.Description = "My test";
            DescriptionChanged = false;
            vm.Description = "My test";

            Assert.IsFalse(DescriptionChanged);
        }

        [TestMethod]
        public void Changing_Description_sets_value()
        {
            vm = new SnippetViewModel();
            vm.Description = "My test";
            Assert.AreEqual(vm.Description, "My test");
        }
        #endregion

        #region AddGroup notification tests
        [TestMethod]
        public void Changing_AddGroup_raises_notification()
        {
            vm = new SnippetViewModel();
            bool AddGroupChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "AddGroup")
                {
                    AddGroupChanged = true;
                }
            };
            vm.AddGroup = true;
            Assert.IsTrue(AddGroupChanged);
        }

        [TestMethod]
        public void Changing_AddGroup_to_the_same_value_does_not_raise_notification()
        {
            vm = new SnippetViewModel();
            bool AddGroupChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "AddGroup")
                {
                    AddGroupChanged = true;
                }
            };
            vm.AddGroup = true;
            AddGroupChanged = false;
            vm.AddGroup = true;

            Assert.IsFalse(AddGroupChanged);
        }

        [TestMethod]
        public void Changing_AddGroup_sets_value()
        {
            vm = new SnippetViewModel();
            vm.AddGroup = true;
            Assert.AreEqual(vm.AddGroup, true);
        }
        #endregion

        #region ChooseGroup notification tests
        [TestMethod]
        public void Changing_ChooseGroup_raises_notification()
        {
            vm = new SnippetViewModel();
            vm.ChooseGroup = false;
            bool ChooseGroupChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "ChooseGroup")
                {
                    ChooseGroupChanged = true;
                }
            };
            vm.ChooseGroup = true;
            Assert.IsTrue(ChooseGroupChanged);
        }

        [TestMethod]
        public void Changing_ChooseGroup_to_the_same_value_does_not_raise_notification()
        {
            vm = new SnippetViewModel();
            bool ChooseGroupChanged = false;
            vm.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == "ChooseGroup")
                {
                    ChooseGroupChanged = true;
                }
            };
            vm.ChooseGroup = true;
            ChooseGroupChanged = false;
            vm.ChooseGroup = true;

            Assert.IsFalse(ChooseGroupChanged);
        }

        [TestMethod]
        public void Changing_ChooseGroup_sets_value()
        {
            vm = new SnippetViewModel();
            vm.ChooseGroup = true;
            Assert.AreEqual(vm.ChooseGroup, true);
        }
        #endregion

    }
}
